Skip to content

Fix Update Packages workflow failures; add Gradle and Mix ecosystem support - #65

Merged
einari merged 3 commits into
mainfrom
fix/update-packages-yarn-immutable-dotnet-tfm-gradle-elixir
Aug 14, 2026
Merged

Fix Update Packages workflow failures; add Gradle and Mix ecosystem support#65
einari merged 3 commits into
mainfrom
fix/update-packages-yarn-immutable-dotnet-tfm-gradle-elixir

Conversation

@einari

@einari einari commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What's broken today

The daily "Update Packages" workflow is failing across most of the org. Diagnosed each failure individually across ~10 affected repos; three root causes are fixable here in the shared workflow:

  1. Yarn immutable installs (Chronicle.TypeScript): GitHub Actions sets CI=true, which makes Yarn Berry default to immutable installs. The yarn install meant to write the lockfile after npm-check-updates bumps package.json refuses ("lockfile would have been modified... explicitly forbidden").
  2. typescript 6→7 vs. Yarn's compat patch (Fundamentals, Components, Workshops): npm-check-updates -u jumps typescript across its 6→7 rewrite (new internal package layout). Yarn Berry's builtin compat/typescript patch hasn't caught up and crashes on install.
  3. dotnet package update hard-aborts on per-TFM version divergence (Arc): exits non-zero with zero changes applied whenever a package has different centrally-managed versions per target framework — which is exactly what Arc's conditional Directory.Packages.NET8-9.props setup does deliberately (documented workaround for a Chronicle bug). The command can't reconcile that, so it's failed the same way every day with nothing anyone can do about it via NuGet alone.

(Other failures — ProtocolGeneration, VerticalSlices, cli — were genuine breaking major-version bumps in application code, not workflow bugs; fixed directly in those repos: Cratis/ProtocolGeneration#8, Cratis/VerticalSlices#13, Cratis/cli#71.)

Fixes

  • YARN_ENABLE_IMMUTABLE_INSTALLS: false on the post-ncu yarn install step.
  • Exclude typescript from the automatic bump (-x typescript) until Yarn ships a compat-patch update for the new TS7 layout.
  • Treat dotnet package update's "is not supported by this command" (per-TFM divergence) as a soft skip instead of a hard failure.

New: Gradle (Kotlin/JVM) and Mix (Elixir) support

Adds two new detected ecosystems alongside the existing NuGet/NPM:

  • Gradle: detected via a root gradlew + settings.gradle(.kts)/build.gradle(.kts). Runs ./gradlew useLatestVersions (via gradle-versions-plugin + gradle-use-latest-versions-plugin, which the target repo declares itself — companion PR: Enable automated dependency updates via gradle-versions-plugin Chronicle.Kotlin#47) then ./gradlew build to verify.
  • Mix: detected via a mix.exs up to 3 directories deep (Elixir repos here nest the package, e.g. Source/chronicle/mix.exs, rather than rooting it), ignoring deps//_build/. Runs mix deps.update --all (respects the ~> constraints already declared in mix.exs) then mix compile to verify.

Both follow the existing NuGet/NPM pattern: only commit and push if the post-update build actually succeeds.

To take effect, Chronicle.Kotlin needs Cratis/Chronicle.Kotlin#47 merged first (declares the two Gradle plugins this relies on). Chronicle.Elixir needs no repo-side changes — mix.exs constraints there are already loose enough for mix deps.update --all to work as-is (verified locally). Chronicle itself is NuGet-only and already works; no changes needed there.

Test plan

  • YAML validated (python3 -c "import yaml; yaml.safe_load(open(...))")
  • Reproduced the Arc dotnet package update per-TFM abort locally against a real clone and confirmed the new soft-skip branch matches the actual error text
  • Reproduced the Gradle useLatestVersions + build cycle locally against a real Chronicle.Kotlin clone (including the stable-only filter correctly skipping a real prerelease build)
  • Reproduced the Mix deps.update --all + compile cycle locally against a real Chronicle.Elixir clone
  • First live scheduled run against each affected repo (will need to monitor after merge)

einari added 3 commits August 14, 2026 11:34
…x support

Three bugs were causing the daily Update Packages workflow to fail
across most of the org:

- Yarn Berry auto-detects GitHub Actions' CI=true and defaults installs
  to immutable, so the yarn install that's supposed to write the
  lockfile after npm-check-updates bumps package.json refuses to do so
  ("lockfile would have been modified... explicitly forbidden"). Set
  YARN_ENABLE_IMMUTABLE_INSTALLS: false for that step.

- npm-check-updates was bumping typescript across its 6->7 rewrite,
  which restructured the published package layout; Yarn Berry's builtin
  compat/typescript patch hasn't been updated for it and crashes on
  install. Excluded typescript from the automatic bump until Yarn ships
  a fix (Fundamentals, Components, Workshops, Chronicle.TypeScript were
  all hitting this).

- `dotnet package update` hard-aborts with no changes applied whenever
  a package has different centrally-managed versions per target
  framework (e.g. Arc deliberately pins System.Text.Json differently
  for net8.0/net9.0 vs net10.0 via conditional Directory.Packages.*.props
  imports, working around a Chronicle bug). That's a legitimate,
  intentional setup the command just can't reconcile - now treated as a
  soft skip instead of a hard failure.

Also adds Gradle (Kotlin/JVM) and Mix (Elixir) as detected ecosystems,
alongside the existing NuGet/NPM support:

- Gradle: detected via a root gradlew + settings/build.gradle(.kts).
  Runs `./gradlew useLatestVersions` (gradle-versions-plugin +
  gradle-use-latest-versions-plugin, which the target repo must declare
  itself - see the companion Chronicle.Kotlin PR) then `./gradlew build`
  to verify.
- Mix: detected via a mix.exs up to 3 directories deep (Elixir repos
  here nest the package rather than rooting it, e.g.
  Source/chronicle/mix.exs), ignoring deps/_build. Runs `mix deps.update
  --all` (respects the ~> constraints already in mix.exs, same
  safety margin NuGet/NPM don't have) then `mix compile` to verify.

Both new ecosystems follow the same pattern as NuGet/NPM: only commit
and push if the post-update build actually succeeds.
Live-tested against Arc and hit a second, different exit-3 failure mode
that the text-match alone didn't cover: a plain NU1109 downgrade
conflict (not the "not supported by this command" message), apparently
from the command bumping one centrally-pinned package without
correctly co-updating a transitively-pinned dependency of it. Same
exit code (3), same "no changes written to disk" behavior, same fix.
Live-tested against Arc and found a third latent bug, previously
masked by the NuGet exit-3 failure: this workflow built .NET before
installing NPM dependencies, but Arc's ProxyGenerator.Specs.csproj has
an MSBuild target that shells out to `yarn build`, so `dotnet build`
failed with "This package doesn't seem to be present in your lockfile"
- node_modules simply didn't exist yet.

Reordered so every ecosystem's setup + dependency-update runs first,
then every ecosystem's build runs afterward, regardless of which
ecosystems are actually detected. This also fixes the equivalent
latent risk for Gradle/Mix repos with cross-ecosystem build-time
dependencies, not just the one now-visible NuGet+NPM case.
@einari
einari merged commit 4f4c30f into main Aug 14, 2026
@einari
einari deleted the fix/update-packages-yarn-immutable-dotnet-tfm-gradle-elixir branch August 14, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant